package io.adrainty.bolee.security.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.adrainty.bolee.framework.commons.basic.ResponseCode;
import io.adrainty.bolee.framework.commons.constants.GlobalOauth2Constants;
import io.adrainty.bolee.framework.commons.exception.AppException;
import io.adrainty.bolee.security.models.bo.RoleDeptBO;
import io.adrainty.bolee.security.models.bo.RoleResourceBO;
import io.adrainty.bolee.security.models.constants.RoleConstants;
import io.adrainty.bolee.security.models.entity.DeptEntity;
import io.adrainty.bolee.security.models.entity.ResourceEntity;
import io.adrainty.bolee.security.models.entity.RoleEntity;
import io.adrainty.bolee.security.repository.IDeptRepository;
import io.adrainty.bolee.security.repository.IResourceRepository;
import io.adrainty.bolee.security.repository.IRoleRepository;
import io.adrainty.bolee.security.service.IRoleService;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author AdRainty
 * @version V1.0.0
 * @since 2025/8/9 下午11:19
 */

@Service
public class RoleServiceImpl implements IRoleService {

    @Resource
    private IRoleRepository roleRepository;

    @Resource
    private IResourceRepository resourceRepository;

    @Resource
    private IDeptRepository deptRepository;

    @Override
    @Cacheable(value = RoleConstants.LIST,key ="#userId")
    public List<RoleEntity> findRoleByUserId(Long userId) {
        return roleRepository.findRoleByUserId(List.of(userId));
    }

    @Override
    public IPage<RoleEntity> findRolePage(RoleEntity entity, Integer pageNum, Integer pageSize) {
        IPage<RoleEntity> pageResult = roleRepository.findRolePage(entity, pageNum, pageSize);
        List<RoleEntity> records = pageResult.getRecords();
        fillRoleData(records);
        return pageResult;
    }

    @Override
    public List<RoleEntity> listRole(RoleEntity entity) {
        List<RoleEntity> records = roleRepository.listRole(entity);
        fillRoleData(records);
        return records;
    }

    @Override
    @Transactional
    public RoleEntity createRole(RoleEntity entity) {
        if (!roleRepository.saveRole(entity)) {
            throw new AppException(ResponseCode.ROLE_CREATE_ERROR);
        }
        saveRoleExtraData(entity);
        return entity;
    }

    @Override
    @Transactional
    public Boolean updateRole(RoleEntity entity) {
        if (entity.getId() == null) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER);
        }

        if (!roleRepository.updateRole(entity)) {
            throw new AppException(ResponseCode.ROLE_UPDATE_ERROR);
        }

        // 删除角色权限关联
        roleRepository.deleteRoleResourceByRoleId(entity.getId());
        roleRepository.deleteRoleDeptByRoleId(entity.getId());
        saveRoleExtraData(entity);
        return true;
    }

    /**
     * 保存角色的额外数据
     * @param entity 角色
     */
    private void saveRoleExtraData(RoleEntity entity) {
        // 保存角色资源中间信息
        if (ArrayUtil.isNotEmpty(entity.getCheckedResourceNos())) {
            List<RoleResourceBO> roleResourceList = Arrays.stream(entity.getCheckedResourceNos()).map(resourceNo ->
                    RoleResourceBO.builder()
                            .roleId(entity.getId())
                            .resourceNo(resourceNo)
                            .build()
            ).toList();
            roleRepository.saveBatchRoleResource(roleResourceList);
        }

        // 保存角色部门中间信息
        if (GlobalOauth2Constants.DATA_SCOPE_1.equals(entity.getDataScope()) && ArrayUtil.isNotEmpty(entity.getCheckedDeptNos())) {
            List<RoleDeptBO> roleDeptList = Arrays.stream(entity.getCheckedDeptNos()).map(deptNo ->
                    RoleDeptBO.builder()
                            .roleId(entity.getId())
                            .deptNo(deptNo)
                            .build()
            ).toList();
            roleRepository.saveBatchRoleDept(roleDeptList);
        }
    }

    /**
     * 填充角色数据
     * @param records 角色列表
     */
    private void fillRoleData(List<RoleEntity> records) {
        if (CollUtil.isEmpty(records)) return;
        List<Long> roleIdList = records.stream().map(RoleEntity::getId).toList();
        Map<Long, List<ResourceEntity>> resourceEntities = resourceRepository.findResourceByRoleIds(roleIdList).stream()
                .filter(r -> r.getRoleId() != null)
                .collect(Collectors.groupingBy(ResourceEntity::getRoleId));
        Map<Long, List<DeptEntity>> deptEntities = deptRepository.findDeptByRoleIds(roleIdList).stream()
                .filter(r -> r.getRoleId() != null)
                .collect(Collectors.groupingBy(DeptEntity::getRoleId));
        for (RoleEntity roleEntity : records) {
            String[] resourceNoArr = resourceEntities.getOrDefault(roleEntity.getId(), new ArrayList<>())
                    .stream().map(ResourceEntity::getResourceNo).toArray(String[]::new);
            roleEntity.setCheckedResourceNos(resourceNoArr);
            String[] deptNoArr = deptEntities.getOrDefault(roleEntity.getId(), new ArrayList<>())
                    .stream().map(DeptEntity::getDeptNo).toArray(String[]::new);
            roleEntity.setCheckedDeptNos(deptNoArr);
        }
    }
}
